// hooks使用

import {useState, useEffect, useMemo, memo, useCallback, useLayoutEffect, useRef} from 'react';

export default function App () {
    const [data, setData] = useState('666');
    const [a, setA] = useState('aa');
    const [b, setB] = useState('bb');
    setTimeout(() => {
        setB('bbb')
    }, 3000)
    return <div>
        {data}
        <Counter/>
        <Parent a={a} b={b}/>
        <CbComponent a={a} b={b}/>
        <MeasureExample />
        <CbCom />
        </div>
}

function Counter() {
    const [count, setCount] = useState(0);
  
    useEffect(() => {
      const id = setInterval(() => {
        /**
         * 直接使用这种方式的话，并不能持续增长，
         * 因为当 effect 执行时，我们会创建一个闭包，并将 count 的值被保存在该闭包当中，
         * 且初值为 0。每隔一秒，回调就会执行 setCount(0 + 1)，因此，count 永远不会超过 1。
         */
        // setCount(count + 1) // 这个 effect 依赖于 `count` state
        // 应该用如下方式
        setCount(count => count + 1); // 这个 effect 不依赖于 `count` state
      }, 1000);
      return () => clearInterval(id);
    }, []); // []表示，只有初次渲染的时候回触发。
    return <h1>{count}</h1>;
}


// useMemo, 用于组件缓存，数据缓存，避免重复渲染，提高性能，同 shouldComponentUpdate, 
// 可用于缓存组件，缓存执行方法，只有当第二个参数改变时，才会触发渲染或者执行
function Child1 (props) {
    console.log('render Child1')
    return <div>{props.a}</div>
}

function Child2 (props) {
    console.log('render Child2')
    return <div>{props.b}</div>
}

function memoFn (b) {
    console.log(b, 'render b') 
}

export function Parent ({ a, b }) {
    // Only re-rendered if `a` changes:
    const child1 = useMemo(() => <Child1 a={a} />, [a]);
    // Only re-rendered if `b` changes:
    const child2 = useMemo(() => <Child2 b={b} />, [b]);
    
    const memoVal = useMemo(() => memoFn(b), [b]);

    return (
      <>
        {child1}
        {child2}
      </>
    )
}

// useCallback  useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
function cbFn1 (a) {
    console.log(a, 'callback a');
}
function cbFn2 (b) {
    console.log(b, 'callback b');
}
function CbComponent({a, b}) {
    const cb1 = useCallback(() => cbFn1(a), [a]);
    const cb2 = useCallback(() => cbFn2(b), [b]);
    
    return <button onClick={cb2}>cb</button>;
}

function MeasureExample() {
    const [rect, ref] = useClientRect();
    return (
      <>
        <h2 ref={ref}>Hello, world</h2>
        {rect !== null &&
          <h2>The above header is {Math.round(rect.height)}px tall</h2>
        }
      </>
    );
}
// 自定义hooks，计算dom高度
function useClientRect() {
    const [rect, setRect] = useState(null);
    const ref = useCallback(node => {
      if (node !== null) {
        setRect(node.getBoundingClientRect());
      }
    }, []);
    return [rect, ref];
}


// useCallback使用场景，应该和memo配套使用，减少组件重复渲染
function PageA (props) {
  const { onClick, children } = props
  console.log(111, props)
  return <div onClick={onClick}>{children}</div>
}

function PageB ({ onClick, name }) {
  console.log(222)
  return <div onClick={onClick}>{name}</div>
}

const PageC = memo(PageB);

function CbCom() {
  const [a, setA] = useState(0)
  const [b, setB] = useState(0)

  const handleClick1 = () => {
    setA(a + 1)
  }

  const handleClick2 = useCallback(() => {
    setB(b + 1)
  }, [b]);

//   const PageC = useMemo(() => <PageB/>, []); // 这样写没用？

  return (
    <>
        <PageA onClick={handleClick1}>{a}</PageA>
        <PageC onClick={handleClick2} name={b} />
    </>
  )
}